package cn.yto.print.socket;

import cn.hutool.json.JSONUtil;
import cn.yto.print.config.EndpointConfigurator;
import cn.yto.print.config.PrintLinkedContext;
import cn.yto.print.config.ThreadPoolManager;
import cn.yto.print.config.i18n.I18nResourceManager;
import cn.yto.print.constants.AssistantConstants;
import cn.yto.print.controller.IndexController;
import cn.yto.print.enums.MessageTypeEnum;
import cn.yto.print.enums.PrintCmdEnum;
import cn.yto.print.enums.ResponseCodeEnum;
import cn.yto.print.model.request.PrintTaskRequest;
import cn.yto.print.model.response.PrintTaskResponse;
import cn.yto.print.service.PrintProduceService;
import cn.yto.print.system.SpringContextHolder;
import cn.yto.print.system.version.KhgjContactManager;
import cn.yto.print.utils.WebSocketUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.UUID;

import static cn.yto.print.enums.PrintCmdEnum.getPrintCmd;

@Slf4j
@Component
@ServerEndpoint(value = "/print", configurator = EndpointConfigurator.class)
public class PrintSocketExtEndpoint {

    @Value("${app.version}")
    private String appVersion;
    @Autowired
    private PrintProduceService printProduceService;
    @Autowired
    private IndexController indexController;

    @OnOpen
    public void onOpen(Session session) {
        String sessionId = UUID.randomUUID().toString();
        session.getUserProperties().put(AssistantConstants.SESSION_ID, sessionId);
        PrintLinkedContext.addSession(sessionId, session);
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        if (StringUtils.isBlank(message)) {
            return;
        }

        // 当天首次操作上传记录日志
        ThreadPoolManager.getExecutorService().execute(KhgjContactManager::firstLogOperate);
        PrintTaskResponse printTaskResponse = new PrintTaskResponse();

        try {
            PrintTaskRequest printTaskRequest = JSONUtil.toBean(message, PrintTaskRequest.class);
            printTaskRequest.setSessionId((String) session.getUserProperties().get(AssistantConstants.SESSION_ID));
            printTaskResponse.setSessionId(printTaskRequest.getSessionId());
            printTaskResponse.setCmd(printTaskRequest.getCmd());

            PrintCmdEnum printCmd = getPrintCmd(printTaskRequest.getCmd());
            if (null == printCmd) {
                printTaskResponse.setCommProperty(ResponseCodeEnum.UNKNOWN);
                SpringContextHolder.getBean(IndexController.class).addConsoleLog(
                        I18nResourceManager.getInstance().get("index.console.unknown"), MessageTypeEnum.WARNING);
                WebSocketUtil.sendSocketMessage(session, printTaskResponse);
                return;
            }

            switch (printCmd) {
                case PRINT:
                    if (!PrintSocketEndpoint.validatePrintTaskRequest(printTaskRequest, printTaskResponse)) {
                        PrintSocketEndpoint.handleParamErrorResponse(printTaskRequest, printTaskResponse);
                        WebSocketUtil.sendSocketMessage(session, printTaskResponse);
                        return;
                    }
                    printProduceService.pushPrintQueue(printTaskRequest);
                    break;
                case STATUS:
                    PrintSocketEndpoint.getPrintPluginStatus(printTaskResponse);
                    SpringContextHolder.getBean(IndexController.class).addConsoleLog(
                            I18nResourceManager.getInstance().get("index.console.status"), MessageTypeEnum.INFO);
                    WebSocketUtil.sendSocketMessage(session, printTaskResponse);
                    break;
                case GET_PRINTER:
                    PrintSocketEndpoint.getLocalPrinterList(printTaskResponse);
                    SpringContextHolder.getBean(IndexController.class).addConsoleLog(
                            I18nResourceManager.getInstance().get("index.console.getPrinter"), MessageTypeEnum.INFO);
                    WebSocketUtil.sendSocketMessage(session, printTaskResponse);
                    break;
                case VERSION:
                    printTaskResponse.setVersion(appVersion);
                    SpringContextHolder.getBean(IndexController.class).addConsoleLog(
                            I18nResourceManager.getInstance().get("index.console.version"), MessageTypeEnum.INFO);
                    WebSocketUtil.sendSocketMessage(session, printTaskResponse);
                    break;
                default:
                    break;
            }
        } catch (Exception e) {
            log.error("接收前端发来的请求处理异常", e);
            printTaskResponse.setCommProperty(ResponseCodeEnum.EXCEPTION);
            WebSocketUtil.sendSocketMessage(session, printTaskResponse);
        }
    }

    @OnClose
    public void onClose(Session session, CloseReason reason) {
        String sessionId = (String) session.getUserProperties().get(AssistantConstants.SESSION_ID);
        log.info("前端打印通道连接断开，会话ID：{}，状态码：{}，关闭原因：{}", sessionId, reason.getCloseCode(), reason.getReasonPhrase());
        try {
            if (session.isOpen()) {
                session.close();
            }
        } catch (Exception e) {
            log.error("前端打印通道关闭连接发生异常", e);
        }
        PrintLinkedContext.removeSession(sessionId);
        String message = String.format(I18nResourceManager.getInstance().get("index.console.disconnect"), PrintLinkedContext.getSessionSize());
        indexController.addConsoleLog(message, MessageTypeEnum.ERROR);
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        log.error("前端打印通道连接发生异常", throwable);
    }

}
